#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

// 共享内存的大小
#define SHM_SIZE 1024
// 共享内存标识符
#define SHM_NAME "shm_example"

// 消息结构
struct message {
    int written; // 作为一个标志，非0：表示可读，0 ：表示可写
    char text[SHM_SIZE - sizeof(int)]; // 实际消息数据
};

// 服务端代码：
void server(struct message* shm) {
    int epfd = epoll_create1(0);
    if (epfd < 0) {
        perror("epoll_create1");
        exit(EXIT_FAILURE);
    }
    
    struct epoll_event ev, events[1];
    ev.events = EPOLLIN; // 只对读操作感兴趣
    ev.data.fd = 0;      // 使用标准输入作为事件

    if (epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &ev) == -1) {
        perror("epoll_ctl: add");
        exit(EXIT_FAILURE);
    }

    while (1) {
        // 只等待一个事件
        int nfds = epoll_wait(epfd, events, 1, 500);
        if (nfds == -1) {
            perror("epoll_wait");
            exit(EXIT_FAILURE);
        }

        // 读取共享内存
        if (shm->written) {
            printf("Server received: %s", shm->text);
            shm->written = 0; // 设置共享内存为可写状态
        }
    }

    close(epfd);
}

// 客户端代码：
void client(struct message* shm) {
    char buf[SHM_SIZE];
    while (1) {
        while (shm->written == 1) {
            sleep(1); // 等待服务器读取消息
        }

        printf("Enter some text: ");
        fgets(buf, sizeof(buf), stdin);

        strncpy(shm->text, buf, sizeof(shm->text));
        shm->written = 1; // 更新标志，标识已写入数据
    }
}

int main() {
    unlink(SHM_NAME);
    int shm_fd = open(SHM_NAME, O_CREAT | O_RDWR, 0666);
    if (shm_fd == -1) {
        perror("shm open");
        return EXIT_FAILURE;
    }

    // 设置共享内存大小
    if (ftruncate(shm_fd, sizeof(struct message)) == -1) {
        perror("ftruncate");
        return EXIT_FAILURE;
    }

    // 将共享内存映射到进程地址空间
    struct message* shm = (struct message*)mmap(NULL, sizeof(struct message),
                               PROT_READ | PROT_WRITE, MAP_SHARED,
                               shm_fd, 0);
    if (shm == MAP_FAILED) {
        perror("mmap");
        return EXIT_FAILURE;
    }

    shm->written = 0;


    pid_t pid = fork();

    if (pid < 0) {
        perror("fork");
        return EXIT_FAILURE;
    }

    if (pid == 0) {
        // 子进程 - 客户端
        client(shm);
    } else {
        // 父进程 - 服务器
        server(shm);
    }

    // 断开共享内存映射
    if (munmap(shm, sizeof(struct message)) == -1) {
        perror("munmap");
        return EXIT_FAILURE;
    }

    // 删除共享内存对象
    if (unlink(SHM_NAME) == -1) {
        perror("shm unlink");
        return EXIT_FAILURE;
    }

    return 0;
}